package com.fight.strive.sys.modules.rbac.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fight.strive.sys.modules.common.PageR;
import com.fight.strive.sys.modules.exception.StriveException;
import com.fight.strive.sys.modules.rbac.dao.RbacUserMapper;
import com.fight.strive.sys.modules.rbac.dto.RbacUserDto;
import com.fight.strive.sys.modules.rbac.entity.RbacUserEntity;
import com.fight.strive.sys.modules.rbac.service.RbacUserDepartmentService;
import com.fight.strive.sys.modules.rbac.service.RbacUserService;
import com.fight.strive.sys.modules.redis.RedisUtils;
import com.fight.strive.sys.utils.CollectionUtils;
import com.fight.strive.sys.utils.DigestUtils;
import com.fight.strive.sys.utils.ObjectUtils;
import com.fight.strive.sys.utils.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.stream.Collectors;

@Service
@Slf4j
public class RbacUserServiceImpl
        extends ServiceImpl<RbacUserMapper, RbacUserEntity>
        implements RbacUserService {

    /**
     * 以ID为键，对应为值，存储用户信息
     */
    private final String idKey = "sys:rbac_user:id";

    /**
     * 用 loginName 为键，ID 为值，存储用户 loginName->ID
     */
    private final String loginNameKey = "sys:rbac_user:login_name";

    @Resource
    private RbacUserDepartmentService rbacUserDepartmentService;

    @Override
    public void saveUser(RbacUserEntity entity) {
        try {
            if (StringUtils.isNotBlank(entity.getPassword())) {
                entity.setPassword(DigestUtils.md5Hex(entity.getPassword()));
            }
            this.saveOrUpdate(entity);
            // 为了使缓存数据完整
            entity = this.getById(entity.getId());
            this.updateCache(entity);
        } catch (DuplicateKeyException e) {
            throw new StriveException("用户账号不能重复");
        }
    }

    @Override
    public RbacUserEntity getByLoginName(String loginName) {
        Long id = RedisUtils.hashGet(loginNameKey, loginName, Long.class);
        if (ObjectUtils.notNull(id)) {
            return this.getUserById(id);
        }
        QueryWrapper<RbacUserEntity> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("login_name", loginName);
        RbacUserEntity entity = this.getOne(queryWrapper, false);
        if (ObjectUtils.notNull(entity)) {
            this.updateCache(entity);
        }
        return entity;
    }

    @Override
    public RbacUserEntity getUserById(Long id) {
        RbacUserEntity entity = RedisUtils.hashGet(idKey, id, RbacUserEntity.class);
        if (ObjectUtils.isNull(entity)) {
            entity = this.getById(id);
            if (ObjectUtils.notNull(entity)) {
                this.updateCache(entity);
            }
        }
        return entity;
    }

    @Override
    public void removeUser(Long id) {
        RbacUserEntity entity = this.getUserById(id);
        this.removeCache(entity);
        this.removeById(id);
    }

    @Override
    public void updateCache(RbacUserEntity entity) {
        if (ObjectUtils.notNull(entity)
                && ObjectUtils.notNull(entity.getId())
                && ObjectUtils.notNull(entity.getLoginName())) {
            RedisUtils.hashPut(idKey, entity.getId(), entity);
            RedisUtils.hashPut(loginNameKey, entity.getLoginName(), entity.getId());
        }
    }

    @Override
    public void removeCache(RbacUserEntity entity) {
        if (ObjectUtils.notNull(entity)
                && ObjectUtils.notNull(entity.getId())
                && ObjectUtils.notNull(entity.getLoginName())) {
            RedisUtils.hashDelete(loginNameKey, entity.getLoginName());
            RedisUtils.hashDelete(idKey, entity.getId());
        }
    }

    @Override
    public IPage<RbacUserDto> listUserByPage(PageR<RbacUserEntity> page) {
        QueryWrapper<RbacUserDto> queryWrapper = new QueryWrapper<>();
        if (ObjectUtils.notNull(page.getCondValue("departmentId"))) {
            queryWrapper.exists("select id from t_sys_rbac_user_department " +
                            "where user_id = t_sys_rbac_user.id and department_id = '{0}'",
                    page.getCondValue("departmentId"));
        }
        if (ObjectUtils.notNull(page.getCondValue("keywords"))) {
            queryWrapper.and(qw -> qw.like("login_name", page.getCondValue("keywords"))
                    .or().like("nick_name", page.getCondValue("keywords"))
                    .or().like("real_name", page.getCondValue("keywords"))
                    .or().like("mobile", page.getCondValue("keywords")));
        }
        queryWrapper.orderByAsc("seq");
        IPage<RbacUserDto> iPage = this.baseMapper.listUserByPage(page, queryWrapper);
        if (CollectionUtils.isNotEmpty(iPage.getRecords())) {
            iPage.setRecords(iPage.getRecords().stream()
                    .peek(item -> item.setDepartments(
                            rbacUserDepartmentService.listDtoByUserId(item.getId())))
                    .collect(Collectors.toList()));
        }
        return iPage;
    }
}
